# -*- coding: utf-8 -*-

"""
Module implementing foreign_song_learningClass.
"""

from PyQt5.QtCore import *
from PyQt5.QtWidgets import QMainWindow, QMessageBox, QLabel, QButtonGroup
from PyQt5.QtNetwork import *
from PyQt5.QtGui import QFontMetrics
from PyQt5.QtWebEngineWidgets import *

from search_result import result
from play_control_thread import *

import time
import json
import webbrowser
import requests

import pykakasi

from Ui_foreign_song_learning import Ui_foreign_song_learningClass

class foreign_song_learningClass(QMainWindow, Ui_foreign_song_learningClass):
    """
    Class documentation goes here.
    """
    def __init__(self, parent=None):
        """
        Constructor
        
        @param parent reference to the parent widget
        @type QWidget
        """
        super(foreign_song_learningClass, self).__init__(parent)
        self.setupUi(self)
        self.lineEdit_search.setPlaceholderText("请输入歌曲")
        self.lineEdit_search.setText("yorushika")
        
        self.metrics = QFontMetrics(self.lineEdit_lrc.font())
        
        self.manager = QNetworkAccessManager(self)
        self.manager.finished.connect(self.replyFinished)
                
        self.pushButton_play.setEnabled(False)
        self.pushButton_next.setEnabled(False)
        self.pushButton_prev.setEnabled(False)
        
        self.play_control = play_control_thread()
        self.play_control.finished.connect(self.ready_to_play)
        
        self.lrc_dict = {}
        self.tran_dict = {}
        self.cookies = {}
        
        self.timer = QTimer()
        self.timer.timeout.connect(self.on_timer_timeout)
        
        self.flag = False     #play control
        self.engineFlag = 0
        
        group_engine = QButtonGroup(self)
        group_speed = QButtonGroup(self)
        
        group_speed.addButton(self.radioButton_low)
        group_speed.addButton(self.radioButton_mid)
        group_speed.addButton(self.radioButton_heigh)
        
        group_engine.addButton(self.radioButton_ncm)
        group_engine.addButton(self.radioButton_qqm)
        
        self.radioButton_ncm.setChecked(True)
        self.radioButton_heigh.setChecked(True)
        
        copyright = QLabel("API 使用自 <a href = \"https://github.com/Binaryify/NeteaseCloudMusicApi\">网易云音乐 Node.js API service</a> 和 <a href = \"https://jsososo.github.io/QQMusicApi/#/\">QQ音乐 Node.js API</a>")
        self.statusBar.addPermanentWidget(copyright)
        copyright.linkActivated.connect(self.openAPI)
        
        self.volume = 100
        
        self.player = None
    
    @pyqtSlot()
    def on_pushButton_search_clicked(self):
        """
        Slot documentation goes here.
        """
        networkManager = QNetworkConfigurationManager()
        
        if not networkManager.isOnline:
            QMessageBox.information(self, "提示", "无网络", QMessageBox.Ok)
            return
        
        if self.engineFlag == 0 or self.engineFlag == 1 or self.engineFlag == 2:
            self.lineEdit_lrc.clear()
            self.lineEdit_pron.clear()
            self.lineEdit_tran.clear()
            
            dlg = result()
            dlg.setWindowModality(Qt.ApplicationModal)
            dlg.selectDone.connect(self.buffAndPlay)
            dlg.handle_search(self.lineEdit_search.text(), self.engineFlag)
            dlg.show()
            
            self.dlg = dlg
        else:
            QMessageBox.critical(self, "error", "未选择引擎", QMessageBox.Ok)
    
    @pyqtSlot()
    def on_radioButton_ncm_clicked(self):
        """
        Slot documentation goes here.
        """
        self.engineFlag = 0
        print("ncm is called")
    
    @pyqtSlot()
    def on_radioButton_qqm_clicked(self):
        """
        Slot documentation goes here.
        """
        if not self.cookies:
            if QMessageBox.information(self, "提示",  "使用QQ音乐接口需要使用服务器预置的QQ号登录\n单击确定弹出登录界面", QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes:
                self.browser = QWebEngineView()
                self.browser.page().profile().cookieStore().cookieAdded.connect(self.__onCookieAdd)
                self.browser.loadFinished.connect(self.getCookie)
            
                self.browser.load(QUrl("https://y.qq.com/"))
                self.browser.show()
            else:
                pass
            
            self.pushButton_search.setEnabled(False)
        else:
            self.pushButton_search.setEnabled(True)
        self.engineFlag = 1
    
    @pyqtSlot()
    def on_radioButton_low_clicked(self):
        """
        Slot documentation goes here.
        """
        if(self.player):
            self.player.set_rate(0.5)
    
    @pyqtSlot()
    def on_radioButton_mid_clicked(self):
        """
        Slot documentation goes here.
        """
        if(self.player):
            self.player.set_rate(0.75)
    
    @pyqtSlot()
    def on_radioButton_heigh_clicked(self):
        """
        Slot documentation goes here.
        """
        if(self.player):
            self.player.set_rate(1)
    
    @pyqtSlot()
    def on_pushButton_volume_clicked(self):
        """
        Slot documentation goes here.
        """
        if not self.horizontalSlider_volume.value() == 0:
            self.horizontalSlider_volume.setValue(0)
        else:
            self.horizontalSlider_volume.setValue(self.volume)
    
    @pyqtSlot(int)
    def on_horizontalSlider_volume_valueChanged(self, value):
        """
        Slot documentation goes here.
        
        @param value DESCRIPTION
        @type int
        """
        self.player.audio_set_volume(value)
        if value <= 5:
            self.pushButton_volume.setText('🔈')
        else:
            self.pushButton_volume.setText('🔊')
            self.volume = value
    
    @pyqtSlot()
    def on_horizontalSlider_sliderReleased(self):
        """
        Slot documentation goes here.
        """
        print (self.horizontalSlider.value())
        self.timer.stop()
        self.player.set_position(self.horizontalSlider.value() / self.horizontalSlider.maximum())
        self.timer.start(100)
        
    @pyqtSlot()
    def on_pushButton_play_clicked(self):
        """
        Slot documentation goes here.
        """
        if(self.player):
            if(self.flag):
                self.timer.stop()
                self.player.pause()
                self.flag = False
                
                self.pushButton_play.setText("播放")
                self.statusBar.showMessage("暂停")
            else:
                self.timer.start(100)
                self.player.set_pause(0)
                self.flag = True
                
                self.pushButton_play.setText("暂停")
                self.statusBar.showMessage("正在播放 %s" % self.songName)
                
                if self.lineEdit_lrc.text().startswith("即将播放"):
                    self.lineEdit_lrc.clear()

                if self.lineEdit_pron.text() == "点击Play按钮播放":
                    self.lineEdit_pron.clear() 

                if self.lineEdit_tran.text() == "若点击后立刻变灰多半是歌曲无版权":
                    self.lineEdit_tran.clear()
        
    def playPause(self):
        if(self.player):
            if(self.flag):
                self.timer.stop()
                self.player.pause()
                self.flag = False
                
                self.pushButton_play.setText("播放")
                self.statusBar.showMessage("暂停")
            else:
                self.timer.start(100)
                self.player.set_pause(0)
                self.flag = True
                
                self.pushButton_play.setText("暂停")
                self.statusBar.showMessage("正在播放 %s" % self.songName)
                
                if self.lineEdit_lrc.text().startswith("即将播放"):
                    self.lineEdit_lrc.clear()

                if self.lineEdit_pron.text() == "点击Play按钮播放":
                    self.lineEdit_pron.clear() 

                if self.lineEdit_tran.text() == "若点击后立刻变灰多半是歌曲无版权":
                    self.lineEdit_tran.clear()
                    
    def translation(self, originstr):
        text = str(originstr)
        kakasi = pykakasi.kakasi()
        
        kakasi.setMode("H","a") # Hiragana to ascii, default: no conversion
        kakasi.setMode("K","a") # Katakana to ascii, default: no conversion
        kakasi.setMode("J","a") # Japanese to ascii, default: no conversion
        kakasi.setMode("r","Hepburn") # default: use Hepburn Roman table
        kakasi.setMode("s", True) # add space, default: no separator
        kakasi.setMode("C", True) # capitalize, default: no capitalize
        
        conv = kakasi.getConverter()
        result = str(conv.do(text))
        return result

    def stop(self):
        self.player.stop()
        self.timer.stop()
        self.pushButton_play.setEnabled(False)
        self.pushButton_play.setText("播放")
        self.statusBar.showMessage("停止", 2000)

    def on_timer_timeout(self):
        try:
            time1 = time.strftime('%M:%S', time.localtime(self.player.get_time()/1000))
        except:
            print("aint ready")
        else:
            self.horizontalSlider.setValue(self.player.get_time())
            
#            print(time1)
            values = [x[1] for x in self.lrc_dict.items() if time1 in x[0]]
            values_tran = [x[1] for x in self.tran_dict.items() if time1 in x[0]]
#            print(self.lrc_dict)
            
            if values:
                if values_tran:
                    if values_tran != '':
                        if self.metrics.width(values[-1]) > self.lineEdit_lrc.width() or self.metrics.width(values_tran[-1]) > self.lineEdit_tran.width() or self.metrics.width(self.translation(values[-1])) > self.lineEdit_pron.width():
                            self.resize(max(self.metrics.width(values[-1]),  self.metrics.width(values_tran[-1]),  self.metrics.width(self.translation(values[-1]))) + 150,  self.height())
                        self.lineEdit_lrc.setText(values[-1])
                        self.lineEdit_pron.setText(self.translation(values[-1]))
                        self.lineEdit_tran.setText(values_tran[-1])
                    else:
                        self.lineEdit_tran.clear()
                else:
                    if self.metrics.width(values[-1]) > self.lineEdit_lrc.width() or self.metrics.width(self.translation(values[-1])) > self.lineEdit_pron.width():
                        self.resize(max(self.metrics.width(values[-1]), self.metrics.width(self.translation(values[-1]))) + 150,  self.height())
                    if values[-1] != '':
                        self.lineEdit_lrc.setText(values[-1])
                        self.lineEdit_pron.setText(self.translation(values[-1]))
                        
                        
            if not self.player.is_playing():
                self.timer.stop()
                if self.flag:
                    self.stop()
            

    def processLyric(self,  res):
        if self.engineFlag == 0:
            lrc = res["lrc"]["lyric"].splitlines()
            lrc_tran = res["tlyric"]["lyric"].splitlines() 
    #this method is better than regexp, but it also make mistakes.
            for i in lrc:
                lrc_word = i.replace("[", "]").strip().split("]")
                print(lrc_word)
                self.lrc_dict[lrc_word[-2]] = lrc_word[-1]
                
            for i in lrc_tran:
                lrc_word = i.replace("[", "]").strip().split("]")
                self.tran_dict[lrc_word[-2]] = lrc_word[-1]
                
            sorted(self.lrc_dict.keys())
            sorted(self.tran_dict.keys())

        else:
            lrc = res["data"]["lyric"].splitlines()
            print(type(lrc))
            lrc_tran = res["data"]["trans"].splitlines()
            
            for i in lrc:
                if i.startswith("[ti:") or i.startswith("[ar:") or i.startswith("[al:") or i.startswith("[by:") or i.startswith("[offset:") or i.startswith("[kana:"):
                    print(i)
                    del i
                    
            for i in lrc:
                lrc_word = i.replace("[", "]").strip().split("]")
                print(lrc_word)
                self.lrc_dict[lrc_word[-2]] = lrc_word[-1]
                
            for i in lrc_tran:
                lrc_word = i.replace("[", "]").strip().split("]")
                self.tran_dict[lrc_word[-2]] = lrc_word[-1]
                
            sorted(self.lrc_dict.keys())
            sorted(self.tran_dict.keys())
        self.pushButton_play.setEnabled(True)

    def replyFinished(self, reply):
        str1 = str(reply.readAll(), encoding='utf-8')
        try:
            res = json.loads(str1)
        except:
                QMessageBox.information(self,  "API error",  "发生了一个无法获取json的异常",  QMessageBox.Ok)
        else:
            self.processLyric(res)
            
    def getLyric(self, str, engineFlag):
        queryData = QUrlQuery()
        
        if engineFlag == 0:
            basestr = QUrl("http://music.163.com/api/song/lyric")
            queryData.addQueryItem("lv", "1")
            queryData.addQueryItem("kv", "1")
            queryData.addQueryItem("tv", "-1")
            queryData.addQueryItem("id", str)
        elif engineFlag == 1:
            basestr = QUrl("http://localhost:3300/lyric")
            queryData.addQueryItem("songmid", str)
        else:
            return
            
        basestr.setQuery(queryData)
        self.manager.get(QNetworkRequest(basestr))
        
    def ready_to_play(self):
        self.pushButton_play.setEnabled(False)
        if not self._timeout:
            self.instance = self.play_control.get_instance()
            self.media = self.play_control.get_media()
            self.player = self.play_control.get_player()
        
            self.getLyric(self.songID, self.engineFlag)
        
            self.horizontalSlider.setMaximum(self.media.get_duration())
        
            self.lrc_dict.clear()
            self.tran_dict.clear()
        
            self.lineEdit_lrc.setText("即将播放 %s" % self.songName)
            self.lineEdit_pron.setText("点击播放按钮播放")
            self.lineEdit_tran.setText("若点击后立刻变灰多半是歌曲无版权")
            self.statusBar.showMessage("即将播放 %s" % self.songName)
        
        else:
            self.lineEdit_lrc.setText("连接超时")
            self.lineEdit_pron.setText("请检查网络连接")
            self.lineEdit_tran.clear()
            self.statusBar.showMessage("不能播放 %s" % self.songName)
            
            self.pushButton_play.setEnabled(False)
    
    def slot_status_change(self, str):
        print(str)
        if str == 'normal':
            self._timeout = False
        elif str == 'abnormal':
            self._timeout = True
        
        if self.play_control.isRunning():
            QMessageBox.information(self,  "超时",  "加载歌曲超时，请检查网络连接后\n再试一次",  QMessageBox.Ok)
            self.play_control.exit()
            print(self.play_control.isRunning())
            return

    def buffAndPlay(self, songID, songName, engineFlag):
        self.pushButton_play.setEnabled(False)
        
        networkManager = QNetworkConfigurationManager()
        
        if not networkManager.isOnline:
            QMessageBox.information(self, "提示", "无网络", QMessageBox.Ok)
            return
        
        else:
            self.dlg.close()
        
            self.play_control.statusSignal.connect(self.slot_status_change)
        
            if self.player and self.player.is_playing():
                print(self.player.is_playing())
                self.playPause()
        
            self.songID = songID
            self.songName = songName
            
            queryData = QUrlQuery()
        
            if engineFlag == 0:
                basestr = QUrl("https://music.163.com/song/media/outer/url")
                queryData.addQueryItem("id", self.songID + '.mp3')
                basestr.setQuery(queryData)
                
                self.play_control.set_property(basestr.toString(), self.volume)
                self.play_control.start()
            elif engineFlag == 1:
                url = "http://localhost:3300/song/urls"

                querystring = {"id":self.songID}
                response = requests.request("GET", url, params=querystring)
                
                res = json.loads(response.text)
                
                if not res["data"][self.songID] == "":
                    self.play_control.set_property(res["data"][self.songID], self.volume)
                    self.play_control.start()
            
    @pyqtSlot()
    def openAPI(self):
        webbrowser.open("https://github.com/Binaryify/NeteaseCloudMusicApi")
        webbrowser.open("https://jsososo.github.io/QQMusicApi/#/")
        
    def __onCookieAdd(self, cookie):
        name = cookie.name().data().decode('utf-8')
        value = cookie.value().data().decode('utf-8')
        self.cookies[name] = value
        
    def getCookie(self):
        cookieStr = ''
        i = 0
        for key, value in self.cookies.items():
            if i == len(self.cookies.items()) - 1:
                cookieStr += (key + '=' + value)
            else:
                 cookieStr += (key + '=' + value + '; ')
            i += 1
            
        print(cookieStr)
        if not cookieStr == '': 
            self.post_inform(cookieStr)
            
    def post_inform(self, cookieStr):
        url = "http://localhost:3300/user/setCookie"

        payload = "{\"data\":\"%s\"}" % cookieStr
        headers = {
            'Content-Type': "application/json",
            'Cache-Control': "no-cache",
            }

        response = requests.request("POST", url, data=payload, headers=headers)

        if response.text == "{\"result\":100,\"data\":\"操作成功\"}":
            self.browser.close()
            print("cookie success")
            self.pushButton_search.setEnabled(True)
        
if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import QApplication

    app = QApplication(sys.argv)
    
    dlg =  foreign_song_learningClass()
    dlg.show()
    
    sys.exit(app.exec_())
